import { ECSErr } from "../err/ECSErr";
import { EventMgr } from "../event/EventMgr";
import { Cls } from "../util/Defined";
import { Logger } from "../util/Logger";
import { Rand } from "../util/Rand";
import { SeedRand } from "../util/SeedRand";
import { TypeUtil } from "../util/TypeUtil";
import { ECSCmpMgr } from "./ECSCmpMgr";
import { ECSEntity } from "./ECSEntity";
import { ECSEntityMgr } from "./ECSEntityMgr";
import { ECSFilterMgr } from "./ECSFilterMgr";
import { ECSSceneCmp } from "./ECSSceneCmp";
import { ECSSys } from "./ECSSys";
import { ECSSysMgr } from "./ECSSysMgr";

/**
 * 场景状态
 */
export const enum ECSSceneState {
	/** 初始化 */
	init = "init",
	/** 运行中 */
	run = "run",
	/** 暂停中 */
	pause = "pause",
	/** 已停止 */
	stop = "stop",
}

/**
 * 场景事件
 */
export enum ECSSceneEvent {
	stateChange = "stateChange",
	beforeUpdate = "beforeUpdate",
	afterUpdate = "afterUpdate",
	frameRateChange = "frameRateChange",
}

declare global {
	/** ECS事件携带数据 */
	interface ECSEventData {
		[ECSSceneEvent.stateChange]: { lastState: ECSSceneState; state: ECSSceneState };
	}
}

/**
 * [ECS]场景
 */
export class ECSScene extends EventMgr<ECSEventData> {
	/** 场景自增id */
	protected static _id: number = 0;
	/** 已启动的场景映射 */
	static readonly sceneMap = new Map<number, ECSScene>();

	/** 场景id */
	id: number;
	/** 最大帧间隔 */
	maxDtMs: number;

	/** 帧速率 */
	protected _frameRate = 1;
	/** 帧速率 */
	get frameRate() {
		return this._frameRate;
	}
	set frameRate(v: number) {
		if (this.frameRate !== v) {
			this._frameRate = v;
			this.send(ECSSceneEvent.frameRateChange);
		}
	}

	/** 帧间隔(秒) */
	readonly dt: number;

	protected _inFrame: boolean;
	/** 当前逻辑在帧循环内 */
	get inFrame() {
		return this._inFrame;
	}

	protected _state = ECSSceneState.init;
	/** 场景状态 */
	get state() {
		return this._state;
	}

	constructor(
		/** 帧间隔(毫秒) */
		readonly dtMs: number
	) {
		super();
		this.dt = dtMs / 1000;
		this.maxDtMs = dtMs * 5;
		this.id = ++ECSScene._id;
	}

	/**
	 * 启动场景
	 */
	start() {
		if (this._state === ECSSceneState.init) {
			this.onStateChange(ECSSceneState.run);
		}
	}

	/**
	 * 暂停场景
	 */
	pause() {
		if (this._state === ECSSceneState.run) {
			this.onStateChange(ECSSceneState.pause);
		}
	}

	/**
	 * 恢复场景
	 */
	resume() {
		if (this._state === ECSSceneState.pause) {
			this.onStateChange(ECSSceneState.run);
		}
	}

	/**
	 * 停止场景
	 */
	stop() {
		if (this._state !== ECSSceneState.stop) {
			this.onStateChange(ECSSceneState.stop);
		}
	}

	protected _lastTime: number = 0;
	/** 上次循环剩下的dtms */
	protected _leftDtMs: number = 0;

	/**
	 * 执行循环
	 * 计算帧间隔
	 */
	loop() {
		const now = Date.now();
		const dt = now - this._lastTime;
		this._lastTime = now;
		this.tick(dt);
	}

	/**
	 * 触发帧
	 * 达到设定的帧间隔则触发一次帧循环
	 * @param dt 帧间隔(毫秒)
	 */
	tick(dt: number) {
		if (this._state !== ECSSceneState.run) return;
		dt = Math.min(this.maxDtMs, dt + this._leftDtMs);
		const dtMs = this.dtMs / this._frameRate;
		while (dt >= dtMs) {
			this.update();
			dt -= dtMs;
		}
		this._leftDtMs = dt;
	}

	/**
	 * 更新帧循环
	 */
	update() {
		this.onUpdate();
	}

	// ============ 生命周期 ============

	protected _runFrame: number = 0;
	protected _runTimeMs: number = 0;
	protected _runTime: number = 0;

	/** 已运行帧数 */
	get runFrame() {
		return this._runFrame;
	}

	/** 已运行时间(豪秒) */
	get runTimeMs() {
		return this._runTimeMs;
	}

	/** 已运行时间(秒) */
	get runTime() {
		return this._runTime;
	}

	/**
	 * 场景状态改变
	 */
	protected onStateChange(state: ECSSceneState) {
		const lastState = this._state;
		this._state = state;
		switch (state) {
			case ECSSceneState.run:
				if (lastState === ECSSceneState.init) {
					this._lastTime = Date.now();
					this.onStart();
				}
				break;
			case ECSSceneState.stop:
				this.onStop();
				break;
		}
		this.send(ECSSceneEvent.stateChange, { lastState, state });
	}

	/**
	 * 场景启动时触发
	 */
	protected onStart() {
		ECSScene.sceneMap.set(this.id, this);
		this._cmpMap.forEach(cmp => {
			cmp.added = true;
			cmp.onAdd?.();
		});
		this.sysMgr.onStart();
	}

	/**
	 * 场景帧循环触发
	 */
	protected onUpdate() {
		this.send(ECSSceneEvent.beforeUpdate);
		this._inFrame = true;

		++this._runFrame;
		this._runTimeMs += this.dtMs;
		this._runTime = this.runTimeMs / 1000;

		//更新过滤器
		this.filterMgr.update();

		//系统循环
		this.sysMgr.update();

		//更新实体/组件/过滤器
		this.entityMgr.update();
		this.cmpMgr.update();
		this.filterMgr.update();
		this.cmpMgr.updateRemove();
		this.entityMgr.updateStart();

		this._inFrame = false;
		this.send(ECSSceneEvent.afterUpdate);
	}

	/**
	 * 场景停止时触发
	 */
	protected onStop() {
		this.offAll();
		this.entityMgr.destroy();
		this.cmpMgr.destroy();
		this.filterMgr.destroy();
		this.sysMgr.destroy();
		this._cmpMap.forEach(cmp => {
			cmp.added = false;
			cmp.onRemove?.();
		});
		this._cmpMap.clear();
		ECSScene.sceneMap.delete(this.id);
	}

	// ============ 工具 ============

	/** 日志工具 */
	readonly logger = new Logger();
	/** 种子随机数 */
	readonly seedRand = new SeedRand();
	/** 随机工具 */
	readonly rand = new Rand(this.seedRand.next.bind(this.seedRand));

	// ============ 管理器 ============

	/** 实体管理器 */
	readonly entityMgr = new ECSEntityMgr(this);
	/** 组件管理器 */
	readonly cmpMgr = new ECSCmpMgr(this);
	/** 过滤器管理器 */
	readonly filterMgr = new ECSFilterMgr(this);
	/** 系统管理器 */
	readonly sysMgr = new ECSSysMgr(this);

	/**
	 * 创建一个实体
	 */
	createEntity() {
		return this.entityMgr.create();
	}

	/**
	 * 通过实体id获取场景中的实体
	 * @param id 实体id
	 */
	getEntity(id: number) {
		return this.entityMgr.get(id);
	}

	/**
	 * 遍历场景里的实体
	 * @param each 返回true时则返回对应实体
	 */
	eachEntity(each: (entity: ECSEntity) => any) {
		return this.entityMgr.each(each);
	}

	/**
	 * 遍历寻找场景里的实体
	 * @param each 返回true时则返回对应实体
	 */
	findEntity(each: (entity: ECSEntity) => any) {
		return this.entityMgr.find(each);
	}

	/**
	 * 移除实体 在帧结束时才会真正从场景中移除
	 * @param entity 实体
	 */
	removeEntity(entity: ECSEntity) {
		return this.entityMgr.remove(entity);
	}

	/**
	 * 添加系统
	 * @param sysType 系统类型
	 */
	addSys<T extends ECSSys>(sysType: Cls<T>) {
		return this.sysMgr.add(sysType);
	}

	/**
	 * 移除系统
	 * @param sysType 系统类型
	 */
	removeSys<T extends ECSSys>(sysType: Cls<T>) {
		return this.sysMgr.remove(sysType);
	}

	// ============ 场景组件 ============

	/** 场景组件映射 */
	protected _cmpMap = new Map<Cls<ECSSceneCmp>, ECSSceneCmp>();

	/**
	 * 是否存在对应类型的场景组件
	 * @param cmpType 场景组件类型
	 */
	hasCmp(cmpType: Cls<ECSSceneCmp>) {
		return this._cmpMap.has(cmpType);
	}

	/**
	 * 获取场景组件
	 * @param cmpType 场景组件类型
	 */
	getCmp<T extends ECSSceneCmp>(cmpType: Cls<T>) {
		return this._cmpMap.get(cmpType) as T;
	}

	/**
	 * 添加场景组件
	 * @param cmpType 场景组件类型
	 */
	addCmp<T extends ECSSceneCmp>(cmp: T) {
		const cmpType = TypeUtil.getCls(cmp);
		if (this._cmpMap.has(cmpType)) {
			throw new ECSErr("已存在相同场景组件类型");
		}

		this._cmpMap.set(cmpType, cmp);
		cmp.scene = this;
		if (this._state != ECSSceneState.init) {
			cmp.added = true;
			cmp.onAdd?.();
		}
		return cmp as T;
	}

	/**
	 * 移除场景组件
	 * @param cmpType 场景组件类型
	 */
	removeCmp(cmp: ECSSceneCmp) {
		if (this._cmpMap.delete(TypeUtil.getCls(cmp))) {
			cmp.added = false;
			cmp.onRemove?.();
			return true;
		}
		return false;
	}
}
